﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoUnzip.Core;
using AutoUnzip.Interfaces;

namespace AutoUnzip.ViewModel
{
    public class ZipEntryViewModel : ViewModelBase, IProgress<long>
    {
        private readonly string baseDir;
        private readonly FileInfo zipFile;
        private readonly IZipSerivce zipSerivce;
        private readonly IFileService fileService;
        private long progress;
        private bool selected;
        private State state;
        private string parentFolderSize;
        private long progressMax = 100;

        public ZipEntryViewModel(string baseDir, FileInfo zipFile, IZipSerivce zipSerivce, IFileService fileService)
        {
            this.baseDir = baseDir;
            this.zipFile = zipFile;
            this.zipSerivce = zipSerivce;
            this.fileService = fileService;
            Selected = true;

            var folderSize = fileService.GetFolderSize(zipFile.Directory);
            ParentFolderSize = Helper.ToReadableSize(folderSize);
        }

        public string ParentFolderSize
        {
            get { return parentFolderSize; }
            set
            {
                if (value == parentFolderSize) return;
                parentFolderSize = value;
                raisePropertyChanged();
            }
        }

        public string FileName
        {
            get { return zipFile.Name; }
        }

        public long ProgressMax
        {
            get { return progressMax; }
            set
            {
                if (value == progressMax) return;
                progressMax = value;
                raisePropertyChanged();
            }
        }

        public long Progress
        {
            get { return progress; }
            set
            {
                if (value == progress) return;
                progress = value;
                raisePropertyChanged();
            }
        }

        public bool Selected
        {
            get { return selected; }
            set
            {
                if (value.Equals(selected)) return;
                selected = value;
                raisePropertyChanged();
            }
        }

        public State State
        {
            get { return state; }
            set
            {
                if (value == state) return;
                state = value;
                raisePropertyChanged();
            }
        }

        public string FullName
        {
            get { return zipFile.FullName; }
        }

        public string RelativePath
        {
            get { return zipFile.FullName.Substring(baseDir.Length + 1, zipFile.FullName.Length - baseDir.Length - 1); }
        }

        public async Task<bool> UnzipAsync(bool shouldDeleteSourceFiles, IReadOnlyList<IStep> tasks, CancellationTokenSource cancellationTokenSource)
        {
            Progress = 0;
            ProgressMax = tasks.Where(task => task.ShouldExecute).Sum(task => task.ProgressMax) + 100;
            string destination = Path.GetDirectoryName(zipFile.FullName);
            bool result = await zipSerivce.UnzipAsync(zipFile.FullName, destination, cancellationTokenSource.Token, this);
            if (result)
            {
                if (shouldDeleteSourceFiles)
                {
                    await DeleteSourceFilesAsync();
                }
                foreach (var step in tasks)
                {
                    if (step.ShouldExecute)
                    {
                        result &= await step.ExecuteAsync(destination, cancellationTokenSource, this);
                    }
                }
            }
            State = result ? State.Success : State.Failed;

            return result;
        }

        private async Task DeleteSourceFilesAsync()
        {
            IEnumerable<string> files = zipSerivce.GetFilesFromArchive(zipFile.FullName);
            await fileService.DeleteFilesAsync(files);
        }

        public void Report(long value)
        {
            Progress += value;
        }
    }

    public enum State
    {
        None,
        Success,
        Failed
    }
}